﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKArchMethodLibrary.Utils;
using YJKRevitCode.RevitDimensionUtility;
using YJKTextDimension.DimCreator;
using YJKView;

namespace YJKTextDimension.Commands
{
	[Regeneration(RegenerationOption.Manual)]
	[Transaction(TransactionMode.Manual)]
	public class CmdQuickDim : YJKCommandManual
	{
		protected override Result YJKExcute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			if (SwitchView.SetUsableView((CmdViewType)9, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			if (AssistFunc.GetCurrentViewLevel(cmdData.Application.ActiveUIDocument.Document) == null)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			List<Wall> list = null;
			while (this.SelectWallsToDim(ref list))
			{
				Transaction transaction = new Transaction(this.m_doc, "QuickDim");
				transaction.Start();
				try
				{
					while (list.Count > 0)
					{
						Wall wall = list[0];
						List<Wall> list2 = new List<Wall>();
						list2.Add(wall);
						List<Wall> list3 = new List<Wall>();
						list3.AddRange(list);
						DimPublicFunc.WallsConnectOneLine(wall, 0, true, list3, ref list2);
						DimPublicFunc.WallsConnectOneLine(wall, 1, true, list3, ref list2);
						this.DimWallsAlong(list2);
						this.DimWallsThick(list2);
						foreach (Wall item in list2)
						{
							list.Remove(item);
						}
					}
					transaction.Commit();
				}
				catch (Exception)
				{
					transaction.RollBack();
					break;
				}
			}
			return base.YJKExcute(cmdData, ref message, elements);
		}

		private void DimWallsAlong(List<Wall> lstDimWall)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			DimPublicFunc.GetWallsEndPoint(lstDimWall, ref xyz, ref xyz2);
			DimPublicFunc.SortPoint(ref xyz, ref xyz2);
			double num = AssistFunc.mmToFeet(1200.0);
			double dOffset = lstDimWall[0].Width / 2.0;
			XYZ dimDirection = this.GetDimDirection(xyz, xyz2, dOffset);
			XYZ ptDim = xyz + dimDirection * num;
			List<ReferenceInfo> list = new List<ReferenceInfo>();
			Line crossLine = YJKLineEx.YJKGetBound(xyz, xyz2);
			List<Grid> list2 = DimPublicFunc.LineCrossGrids(this.m_uiApp, xyz, xyz2);
			if (list2 != null && list2.Count > 0)
			{
				foreach (Grid grid in list2)
				{
					DimPublicFunc.GetGridDimRef(this.m_uiApp, grid, crossLine, ref list);
				}
			}
			foreach (Wall wall in lstDimWall)
			{
				DimPublicFunc.GetWallDimRef(this.m_uiApp, wall, crossLine, true, ref list);
			}
			XYZ pt = xyz2 + (xyz2 - xyz);
			list.Sort(new DistanceComparer(DimPublicFunc.To2d(pt)));
			ReferenceArray referenceArray = new ReferenceArray();
			foreach (ReferenceInfo referenceInfo in list)
			{
				referenceArray.Append(referenceInfo.TheReference);
			}
			string text = "DoorWindowDim";
			this.DeleteWallDims(lstDimWall, text);
			Dimension dimension = DimPublicFunc.CreateLinearDim(this.m_doc, referenceArray, ptDim, dimDirection, DimensionTypeEnum.ScaleDimension);
			if (dimension != null)
			{
				DimPublicFunc.SetDimFlag(dimension, text);
				DimPublicFunc.SetDimWallId(dimension, lstDimWall[0].Id);
			}
		}

		private void DimWallsThick(List<Wall> lstDimWall)
		{
			XYZ xyz = null;
			XYZ xyz2 = null;
			DimPublicFunc.GetWallsEndPoint(lstDimWall, ref xyz, ref xyz2);
			DimPublicFunc.SortPoint(ref xyz, ref xyz2);
			XYZ xyz3 = xyz + (xyz2 - xyz) / 2.0;
			XYZ xyz4 = (xyz2 - xyz).Normalize();
			XYZ xyz5 = Geometry.RotateTo(xyz4, Math.PI*.5, XYZ.BasisZ);
			xyz = xyz3 + xyz5 * lstDimWall[0].Width;
			xyz2 = xyz3 - xyz5 * lstDimWall[0].Width;
			List<ReferenceInfo> list = new List<ReferenceInfo>();
			Line crossLine = YJKLineEx.YJKGetBound(xyz, xyz2);
			List<Wall> list2 = DimPublicFunc.LineCrossWalls(this.m_uiApp, lstDimWall, xyz, xyz2);
			if (list2 != null && list2.Count > 0)
			{
				DimPublicFunc.GetWallThickRef(this.m_uiApp, list2[0], crossLine, this.m_doc.ActiveView.DetailLevel, ref list);
			}
			List<Grid> list3 = DimPublicFunc.LineCrossGrids(this.m_uiApp, xyz, xyz2);
			if (list3 != null && list3.Count > 0)
			{
				DimPublicFunc.GetGridDimRef(this.m_uiApp, list3[0], crossLine, ref list);
			}
			if (list.Count < 1)
			{
				return;
			}
			ReferenceArray referenceArray = new ReferenceArray();
			foreach (ReferenceInfo referenceInfo in list)
			{
				referenceArray.Append(referenceInfo.TheReference);
			}
			string text = "WallThickDim";
			this.DeleteWallDims(lstDimWall, text);
			Dimension dimension = DimPublicFunc.CreateWallThickDim(this.m_doc, referenceArray, xyz3, xyz4);
			if (dimension != null)
			{
				DimPublicFunc.SetDimFlag(dimension, text);
				DimPublicFunc.SetDimWallId(dimension, lstDimWall[0].Id);
			}
		}

		private bool SelectWallsToDim(ref List<Wall> lstDimWall)
		{
			try
			{
				Assist.WallFilter wallFilter = new Assist.WallFilter();
				IList<Element> list = this.m_uiDoc.Selection.PickElementsByRectangle(wallFilter, "请框选需要进行标注的墙体（只支持直线型墙体）：");
				lstDimWall = new List<Wall>();
				foreach (Element element in list)
				{
					if (element.GetType() == typeof(Wall))
					{
						lstDimWall.Add(element as Wall);
					}
				}
				DimPublicFunc.ClearSurfaceWall(ref lstDimWall);
			}
			catch
			{
				return false;
			}
			return true;
		}

		private XYZ GetDimDirection(XYZ pt1, XYZ pt2, double dOffset)
		{
			DimPublicFunc.SortPoint(ref pt1, ref pt2);
			XYZ xyz = (pt2 - pt1).Normalize();
			xyz = Geometry.RotateTo(xyz, Math.PI*.5, XYZ.BasisZ);
			List<Wall> list = DimPublicFunc.LineCrossWalls(this.m_uiApp, pt1 + xyz * dOffset, pt2 + xyz * dOffset);
			List<Wall> list2 = DimPublicFunc.LineCrossWalls(this.m_uiApp, pt1 - xyz * dOffset, pt2 - xyz * dOffset);
			if (list != null && list.Count > 0)
			{
				if (list2 != null && list2.Count > 0)
				{
					if (pt2.Y - pt1.Y > YJKCommandManual.precision)
					{
						xyz *= -1.0;
					}
				}
				else
				{
					xyz *= -1.0;
				}
			}
			return xyz;
		}

		private void DeleteWallDims(List<Wall> lstWall, string sDimFalg)
		{
			List<Dimension> curViewDims = DimPublicFunc.GetCurViewDims(this.m_uiApp);
			if (curViewDims == null)
			{
				return;
			}
			List<Dimension> list = new List<Dimension>();
			foreach (Wall wall in lstWall)
			{
				Dimension dimOfWall = this.GetDimOfWall(curViewDims, wall.Id, sDimFalg);
				if (dimOfWall != null && !list.Contains(dimOfWall))
				{
					list.Add(dimOfWall);
				}
			}
			foreach (Dimension dim in list)
			{
				if (sDimFalg == "WallThickDim")
				{
					this.DeleteDimAssistLine(dim);
				}
			}
		}

		private void DeleteDimAssistLine(Dimension dim)
		{
			if (dim.References != null)
			{
				foreach (object obj in dim.References)
				{
					Reference reference = (Reference)obj;
					Element elementById = this.m_doc.GetElementById(reference.ElementId);
					if (elementById != null)
					{
						ModelCurve modelCurve = elementById as ModelCurve;
						if (modelCurve != null)
						{
							Line line = modelCurve.GeometryCurve as Line;
							if (!(line == null) && line.Length < 1.0)
							{
								this.m_doc.Delete(reference.ElementId);
							}
						}
					}
				}
			}
		}

		private Dimension GetDimOfWall(List<Dimension> lstAllDim, ElementId wallId, string sDimFalg)
		{
			foreach (Dimension dimension in lstAllDim)
			{
				if (DimPublicFunc.GetDimFlag(dimension) == sDimFalg && DimPublicFunc.GetDimWallId(dimension) == wallId)
				{
					return dimension;
				}
			}
			return null;
		}
	}
}
